package com.alldios.deposit.api;

import com.alibaba.fastjson.JSON;
import com.alldios.deposit.tools.Md5Utils;
import com.alldios.deposit.tools.ReflectionUtils;
import com.alldios.deposit.tools.SpringContextHolder;
import org.apache.commons.lang.StringUtils;
import org.apache.http.HttpStatus;
import org.apache.http.NameValuePair;
import org.apache.http.client.entity.UrlEncodedFormEntity;
import org.apache.http.client.methods.CloseableHttpResponse;
import org.apache.http.client.methods.HttpPost;
import org.apache.http.impl.client.CloseableHttpClient;
import org.apache.http.impl.client.HttpClients;
import org.apache.http.message.BasicNameValuePair;
import org.apache.http.util.EntityUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import javax.servlet.http.HttpServletRequest;
import java.io.IOException;
import java.lang.reflect.Field;
import java.util.ArrayList;
import java.util.List;


public class HfTools {

    static HfDefines defines = SpringContextHolder.getBean(HfDefines.class);
    private static Logger logger = LoggerFactory.getLogger(HfTools.class);


    public static String form(HfReq req) {

        sign(req);
        StringBuffer buffer = new StringBuffer();
        Class<?> superClass = req.getClass().getSuperclass();
        for (Field field : superClass.getDeclaredFields()) {
            buffer.append("\n<input type=\"hidden\" name=\"" + field.getName() + "\" value='" + StringUtils.trimToEmpty((String) ReflectionUtils.getFieldValue(req, field.getName())) + "'/>");
        }
        for (Field field : req.getClass().getDeclaredFields()) {
            buffer.append("\n<input type=\"hidden\" name=\"" + field.getName() + "\" value='" + StringUtils.trimToEmpty((String) ReflectionUtils.getFieldValue(req, field.getName())) + "'/>");
        }
        return "<form id=\"f\" action=\"" + defines.getGateway() + "\" method=\"post\">" + buffer.toString() + "</form>";
    }


    public static <T extends HfResp> T send(HfReq req, Class<T> clazz) {
        sign(req);
        CloseableHttpClient client = null;
        CloseableHttpResponse response = null;
        try {
            client = HttpClients.createDefault();
            HttpPost post = new HttpPost(defines.getGateway());
            UrlEncodedFormEntity formEntity = new UrlEncodedFormEntity(convert(req), "UTF-8");
            post.setEntity(formEntity);
            response = client.execute(post);
            if (response.getStatusLine().getStatusCode() == HttpStatus.SC_OK) {
                String result = EntityUtils.toString(response.getEntity(), "UTF-8");
                T resp = JSON.parseObject(result, clazz);
                if (verify(resp)) {
                    logs(req, resp);
                }
                return resp;
            } else {
                logger.error("汇付请求失败--》{}", response.getStatusLine().getStatusCode());
            }
        } catch (IOException e) {
            e.printStackTrace();
        } finally {
            try {
                if (response != null) {
                    response.close();
                }
                if (client != null) {
                    client.close();
                }
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
        return null;
    }


    private static void logs(Object req, Object resp) {

    }


    private static List<NameValuePair> convert(Object object) {
        List<NameValuePair> pairs = new ArrayList<>();
        Class<?> superClass = object.getClass().getSuperclass();
        if (superClass.getSimpleName().equals("HfReq")) {
            for (Field field : superClass.getDeclaredFields()) {
                pairs.add(new BasicNameValuePair(field.getName(), StringUtils.trimToEmpty((String) ReflectionUtils.getFieldValue(object, field.getName()))));
            }
            for (Field field : object.getClass().getDeclaredFields()) {
                pairs.add(new BasicNameValuePair(field.getName(), StringUtils.trimToEmpty((String) ReflectionUtils.getFieldValue(object, field.getName()))));
            }
        }
        return pairs;
    }


    public static <T extends HfResp> T convert(HttpServletRequest request, Class<T> t) {
        try {
            Object obj = t.newInstance();
            for (Field field : t.getSuperclass().getDeclaredFields()) {
                ReflectionUtils.setFieldValue(obj, field.getName(), StringUtils.trimToEmpty(request.getParameter(field.getName())));
            }
            for (Field field : t.getDeclaredFields()) {
                ReflectionUtils.setFieldValue(obj, field.getName(), StringUtils.trimToEmpty(request.getParameter(field.getName())));
            }
            return (T) obj;
        } catch (InstantiationException | IllegalAccessException e) {
            e.printStackTrace();
        }
        return null;
    }


    private static void sign(HfReq req) {
        String className = req.getClass().getSimpleName();
        req.CmdId = className.substring(0, className.length() - 3);
        StringBuilder buffer = new StringBuilder();
        String[] signList = (String[]) ReflectionUtils.invokeMethod(req, "signList", null, null);
        for (String signFiled : signList) {
            buffer.append(StringUtils.trimToEmpty((String) ReflectionUtils.getFieldValue(req, signFiled.trim())));
        }
        try {
            String content = buffer.toString();
            if (req.needEncrypt()) {
                content = Md5Utils.md5(buffer.toString(), "UTF-8").toLowerCase();
            }
            req.ChkValue = defines.encrypt(content);

        } catch (Exception e) {
            e.printStackTrace();
        }
    }


    public static boolean verify(HfResp resp) {
        if (resp == null) {
            return false;
        }
        StringBuilder buffer = new StringBuilder();
        String[] signList = (String[]) ReflectionUtils.invokeMethod(resp, "signList", null, null);
        for (String signFiled : signList) {
            buffer.append(StringUtils.trimToEmpty((String) ReflectionUtils.getFieldValue(resp, signFiled.trim())));
        }
        try {
            String content = buffer.toString();
            if (resp.needEncrypt()) {
                content = Md5Utils.md5(buffer.toString(), "UTF-8").toLowerCase();
            }
            return defines.verify(content, resp.ChkValue);
        } catch (Exception e) {
            e.printStackTrace();
            return false;
        }
    }

}
